#include<pthread.h>
#include<mutex>
#include<algorithm>
#include<iostream>
using namespace std;

namespace Mango
{

//auto_ptr:通过资源所有权转移的方式让一个资源只能被一个对象管理
template<class T>
class auto_ptr
{
public:
  auto_ptr(T* ptr = nullptr) :_ptr(ptr)
  {}
  ~auto_ptr()
  {
    if(_ptr)
      delete _ptr;
    _ptr = nullptr;
  }
  auto_ptr(const auto_ptr<T>& ap) :_ptr(ap._ptr)
  {
    ap._ptr = nullptr;
  }
  auto_ptr<T>& operator=(const auto_ptr<T>& ap)
  {
    if(this != &ap)
    {
      _ptr = ap._ptr;
      ap._ptr = nullptr;
    }
    return *this;
  }
  T* operator->()
  {
    return _ptr;
  }
  T& operator*()
  {
    return *_ptr;
  }
private:
  T* _ptr;
};


//unique_ptr/scoped_ptr：通过防拷贝的方式，让一个资源只能被一个对象所管理
//二者的区别:unique_ptr不支持拷贝，但是可以进行移动拷贝/赋值
template<class T>
class unique_ptr
{
public:
  unique_ptr(T* ptr = nullptr) :_ptr(ptr)
  {}
  ~unique_ptr()
  {
    if(_ptr) delete _ptr;
    _ptr = nullptr;
  }

  unique_ptr(const unique_ptr<T>&) = delete;
  unique_ptr<T>& operator=(unique_ptr<T>&) = delete;

  unique_ptr(unique_ptr<T>&& up)
  {
    _ptr = up._ptr;
    up._ptr = nullptr;
  }
  unique_ptr<T>& operator=(unique_ptr<T>&& up)
  {
    //注意：是判断二者是否指向同一个资源 ,当然也可以写成是否是同一个对象
    //因为unique_ptr一个资源只有一个对象管理
    if(_ptr != up._ptr) //if(this != &up)
    {
      delete _ptr;
      _ptr = nullptr;

      _ptr = up._ptr;
      up._ptr = nullptr;
    }
    return *this;
  }
  T* operator->()
  {
    return _ptr;
  }
  T& operator*()
  {
    return *_ptr;
  }
private:
  T* _ptr;
};

template<class T>
class shared_ptr
{
public:
  shared_ptr(T* ptr = nullptr) :_ptr(ptr)
  {
    if(_ptr != nullptr)
    {
      _pRefCount = new int(1);
      _mtx = new mutex();
    }
  }
  ~shared_ptr()
  {
    ReleaseRef();
  }
  shared_ptr(const shared_ptr<T>& sp) :_ptr(sp._ptr),_pRefCount(sp._pRefCount),_mtx(sp._mtx)
  {
     AddRef();
  }
  shared_ptr<T>& operator=(const shared_ptr<T>& sp)
  {
    //判断是否管理资源,而不是判断二者是否是相同的对象,可以提高效率！
    if(_ptr != sp._ptr)
    {
      ReleaseRef(); 
      _ptr = sp._ptr;
      _pRefCount = sp._pRefCount;
      _mtx = sp._mtx;

      AddRef();
    }

    return *this;
  }
  //unique_lock和lock_guard管理的都是mutex互斥锁对象
  void AddRef()
  {
    lock_guard<mutex> lg(*_mtx);
    (*_pRefCount)++;
  }
  void ReleaseRef()
  {
    unique_lock<mutex> ul(*_mtx);
    bool flag = false;
    if(--(*_pRefCount) == 0 && _ptr)
    {
      delete _ptr;
      delete _pRefCount;
      _ptr = _pRefCount = nullptr;
      flag = true;
    }
    if(flag)
    {
      ul.unlock();
      delete _mtx;
      _mtx = nullptr;
    }
  }
  T* operator->()
  {
    return _ptr;
  }
  T& operator*()
  {
    return *_ptr;
  }
  T* get() 
  {
    return _ptr;
  }
  int use_count()
  {
    return *_pRefCount;
  }
private:
  T* _ptr;
  int* _pRefCount;
  mutex* _mtx;
};


template<class T>
class weak_ptr
{
public:
  weak_ptr() :_ptr(nullptr)
  {}
  weak_ptr(const shared_ptr<T>& sp) :_ptr(sp.get())
  {}
  weak_ptr(const weak_ptr<T>& wp) :_ptr(wp.get())
  {}
  weak_ptr<T>& operator=(const weak_ptr<T>& wp)
  {
    _ptr = wp.get();
    return *this;
  }
  T* get()
  {
    return _ptr;
  }
private:
  T* _ptr;
};

}
